import {
	Color,
	PolygonHierarchy,
	Cartesian3,
	HeadingPitchRange,
	CallbackProperty,
	Math as cesiumMath,
	Rectangle,
	NearFarScalar,
	ColorMaterialProperty,
	Transforms,
	Matrix4,
	Cartographic,
	Cartesian2,
	ImageMaterialProperty,
	LineFlowMaterialProperty,
	PolylineGlowMaterialProperty,
	PolylineDashMaterialProperty,
	PolylineTrailLinkMaterialProperty,
	CircleWaveMaterialProperty,
} from "cesium";
import { lngLatsToCartesian3Array, lngLatToCartesian3, lngLatValid } from "./coordinate";
import { setDefaultValue, isUndefined } from "./common";

export const callbackItem = ({ fn = () => {}, isConstant = false }) => {
	fn._generator = callback;
	fn.once = true;
	fn.isConstant = isConstant;
	return fn;
};

export const callback = function () {
	const { isConstant } = this;
	return new CallbackProperty(fn, isConstant);
};

/**
 * @name 根据lnglat生成三维坐标
 * @param {*} param0
 * @returns
 */
export const positionItem = ({ lng, lat, height }) => {
	lngLatValid(lng, lat);
	return {
		lng,
		lat,
		height: setDefaultValue(height, 0),
		_generator: position,
	};
};
export const position = function () {
	const { lng, lat, height } = this;
	return Cartesian3.fromDegrees(lng, lat, height);
};
/**
 * @name 根据lnglat数组生成三维坐标数组
 * @param {*} positionArr
 * @returns
 */
export const positionsItem = (positionArr = [], callback = false) => {
	positionArr = [...positionArr];
	positionArr._generator = positions;
	positionArr.once = positionArr._callback = callback;
	return positionArr;
};

export const positions = function () {
	return new CallbackProperty(() => {
		return this.map(lngLatToCartesian3);
	}, !this._callback);
};
/**
 * @name 虚线
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @returns
 */
export const dashMaterialItem = ({ color, ...options } = {}) => {
	return {
		color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
		...options,
		_generator: dashMaterialProperty,
	};
};

export const dashMaterialProperty = function () {
	const { color, glowPower, taperPower, _callback } = this;
	if (!_callback) {
		return new PolylineDashMaterialProperty({
			color: Color.fromCssColorString(this.color),
			glowPower: this.glowPower,
			taperPower: this.taperPower,
		});
	}
	return new PolylineDashMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				glowPower: this.glowPower,
				taperPower: this.taperPower,
			};
			//   color: Color.fromCssColorString(this.color);
		}, false)
	);
};
/**
 * @name 发光线
 */
export const materialPropertyItem = ({ color, ...options } = {}) => {
	return {
		color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
		...options,
		_generator: materialProperty,
	};
};

export const materialProperty = function () {
	const { color, glowPower, taperPower, _callback } = this;
	if (!_callback) {
		return new PolylineGlowMaterialProperty({
			color: Color.fromCssColorString(this.color),
			glowPower: this.glowPower,
			taperPower: this.taperPower,
		});
	}
	return new PolylineGlowMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				glowPower: this.glowPower,
				taperPower: this.taperPower,
			};
			//   color: Color.fromCssColorString(this.color);
		}, false)
	);
};

/**
 * @name 添加图片材质
 * @param {String} image
 * @param {Array} repeat new Cartesian2(1.0, 1.0)
 * @param {String} color Color.WHITE
 * @param {String} transparent Color.WHITE
 */
export const materialImageMaterialPropertyItem = ({ color, image, repeat, transparent, ...options } = {}) => {
	return {
		image,
		repeat,
		color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
		...options,
		_generator: materialImageMaterialProperty,
	};
};

export const materialImageMaterialProperty = function () {
	const { color, image, repeat, transparent, _callback } = this;
	if (!_callback) {
		return new ImageMaterialProperty({
			color: Color.fromCssColorString(this.color),
			glowPower: this.glowPower,
			taperPower: this.taperPower,
			image: this.image,
			transparent: this.transparent,
			repeat: this.repeat,
			taperPower: this.taperPower,
		});
	}
	return new ImageMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				image: this.image,
				transparent: this.transparent,
				repeat: this.repeat,
				taperPower: this.taperPower,
			};
		}, false)
	);
};

/**
 * @name 添加流动材质
 * @param {String} image
 * @param {String} color Color.WHITE
 * @param {String} duration 时间
 */
export const materialPolylineTrailLinkMaterialPropertyItem = ({ color, image, duration, ...options } = {}) => {
	return {
		// image: setDefaultValue(image, "/bx-dashboard/imgs/cz.png"),
		duration: setDefaultValue(duration, 4000),
		color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
		...options,
		_generator: materialPolylineTrailLinkMaterialProperty,
	};
};

export const materialPolylineTrailLinkMaterialProperty = function () {
	const { color, image, duration, transparent, _callback } = this;
	if (!_callback) {
		return new PolylineTrailLinkMaterialProperty({
			color: Color.fromCssColorString(this.color),
			image: this.image,
			duration: this.duration,
		});
	}
	return new PolylineTrailLinkMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				image: this.image,
				duration: this.duration,
				repeat: this.repeat,
				taperPower: this.taperPower,
			};
		}, false)
	);
};

/**
 * @name 添加圆点扩散材质
 * @param {String} height  高度
 * @param {String} semiMinorAxis  长半轴
 * @param {String} semiMajorAxis  短半轴
 * @param {String} color Color.WHITE
 * @param {Number} duration 速度
 * @param {String} gradient 渐变
 * @param {String} count 数量
 */
export const materialCircleWaveMaterialItem = ({ color, height, duration, gradient, count, ...options } = {}) => {
	return {
		height: setDefaultValue(height, 0),
		duration: setDefaultValue(duration, 5000.0),
		gradient: setDefaultValue(gradient, 0.5),
		count: setDefaultValue(count, 1),
		color: setDefaultValue(color, "rgba(0,175,255,0.9)"),
		...options,
		_generator: materialCircleWaveMaterial,
	};
};

export const materialCircleWaveMaterial = function () {
	const { color, height, semiMinorAxis, semiMajorAxis, duration, gradient, count, _callback } = this;
	if (!_callback) {
		return new CircleWaveMaterialProperty({
			color: Color.fromCssColorString(this.color),
			height: this.height,
			duration: this.duration,
			gradient: this.gradient,
			count: this.count,
		});
	}
	return new CircleWaveMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				height: this.height,
				duration: this.duration,
				gradient: this.gradient,
				count: this.count,
			};
		}, false)
	);
};

/**
 * @name 创建飞线
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @param {String} obj.speed 速度
 * @returns
 */
export const lineFlowMaterialItem = ({ color, ...options } = {}) => {
	return {
		color: setDefaultValue(color, "rgba(255,0,0,0.5)"),
		speed: 4,
		...options,
		_generator: lineFlowMaterial,
	};
};

export const lineFlowMaterial = function () {
	const { color, speed, _callback } = this;
	if (!_callback) {
		return new LineFlowMaterialProperty({
			color: Color.fromCssColorString(this.color),
			speed: this.speed,
			percent: 0.1,
			gradient: 0.01,
		});
	}
	return new LineFlowMaterialProperty(
		new CallbackProperty(() => {
			return {
				color: Color.fromCssColorString(this.color),
				speed: this.speed,
				percent: 0.1,
				gradient: 0.01,
			};
		}, false)
	);
};

/**
 * @name 根据颜色对象生成材质
 * @param {Object} obj
 * @param {String} obj.color 16进制颜色
 * @returns
 */

export const materialColorItem = ({ color, ...options } = {}) => {
	return {
		color: setDefaultValue(color, "rgba(255,0,0,0.5)"),
		...options,
		_generator: materialColor,
	};
};

export const materialColor = function () {
	const { color, _callback } = this;
	if (!_callback) {
		return Color.fromCssColorString(this.color);
	}
	return new ColorMaterialProperty(
		new CallbackProperty(() => {
			return Color.fromCssColorString(this.color);
		}, false)
	);
};

/**
 * @name 根据层级对象生成层级
 * @param {Object} obj
 * @param {String} obj._callback 是否动态生成器
 * @param {Array<Object>} obj.positions 外围经纬度坐标
 * @param {Array<Object>} obj.holes 中间的洞的经纬度坐标
 * @returns
 */

export const polygonHierarchyItem = ({ holes, positions, _callback, ...options } = {}) => {
	return {
		_callback: Boolean(_callback),
		holes: holes || [],
		positions: positions || [],
		...options,
		_generator: polygonHierarchy,
	};
};

export const polygonHierarchy = function () {
	let { _callback, positions, holes } = this;
	positions = setDefaultValue(positions, []);
	holes = setDefaultValue(holes, []);
	if (_callback) {
		return new CallbackProperty(() => {
			return new PolygonHierarchy(lngLatsToCartesian3Array(positions), lngLatsToCartesian3Array(holes));
		}, false);
	}
	return new PolygonHierarchy(lngLatsToCartesian3Array(positions), lngLatsToCartesian3Array(holes));
};

/**
 * @name 生成HPR
 * @param {Object} obj
 * @returns
 */

export const headingPitchRangeItem = ({ heading, pitch, range, _callback, ...options } = {}) => {
	return {
		heading: setDefaultValue(heading, 0),
		pitch: setDefaultValue(pitch, 0),
		range: setDefaultValue(range, 0),
		_callback: setDefaultValue(_callback, false),
		...options,
		_generator: headingPitchRange,
	};
};

export const headingPitchRange = function () {
	const { _callback, heading, pitch, range } = this;
	if (_callback) {
		return new CallbackProperty(() => {
			return new HeadingPitchRange(Math.toRadians(obj.heading), Math.toRadians(obj.pitch), obj.range);
		}, false);
	}
	return new HeadingPitchRange(Math.toRadians(heading), Math.toRadians(pitch), Math.toRadians(range));
};

/**
 * @name 生成长方体
 * @param {Object} obj
 * @returns
 */
export const rectangleItem = ({ west, south, east, north, _callback, ...options } = {}) => {
	return {
		west: setDefaultValue(west, 0),
		south: setDefaultValue(south, 0),
		east: setDefaultValue(east, 0),
		north: setDefaultValue(north, 0),
		...options,
		_generator: rectangle,
	};
};

export const rectangle = function () {
	const { _callback, west, south, east, north } = this;
	if (_callback) {
		return new CallbackProperty(() => {
			return new Rectangle(Math.toRadians(obj.west), Math.toRadians(obj.south), Math.toRadians(obj.east), Math.toRadians(obj.north));
		}, false);
	}
	return new Rectangle(Math.toRadians(west), Math.toRadians(south), Math.toRadians(east), Math.toRadians(north));
};

/**
 * @name 生成缩放参数
 * @param {Object} obj
 * @returns
 */
export const nearFarScalarItem = ({ near, nearValue, far, farValue } = {}) => {
	return {
		near: setDefaultValue(near, 0),
		nearValue: setDefaultValue(nearValue, 0),
		far: setDefaultValue(far, 0),
		farValue: setDefaultValue(farValue, 0),
		_generator: nearFarScalar,
	};
};

export const nearFarScalar = function () {
	const { near, nearValue, far, farValue } = this;
	return new NearFarScalar(near, nearValue, far, farValue);
};

export const generate = (data) => {
	if (data?._generator) {
		return data._generator.call(data);
	} else if (!data instanceof Function && data instanceof Object) {
		return JSON.parse(JSON.stringify(data));
	} else {
		return data;
	}
};

export const mergeEntity = (options, entity) => {
	Object.keys(options).forEach((key) => {
		if (options[key]?.once && entity[key]) {
			return;
		}
		entity[key] = generate(options[key]);
	});
};

export const computeCircle = (radius) => {
	const positions = [];
	for (let i = 0; i < 360; i++) {
		const radians = cesiumMath.toRadians(i);
		positions.push(new Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians)));
	}
	return positions;
};
